﻿//#define DEBUG1
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using DirectUI.Mobile.UI.Drawing.GdiPlus;
using System.Collections.Specialized;
using System.Diagnostics;
using Microsoft.WindowsCE.Forms;
namespace DirectUI.Mobile.UI.Controls
{
    /// <summary>
    /// A control that contains other DirectUI controls.
    /// </summary>
    public partial class ScrollPanel : ScrollContainer, IMultiControlContainer, ICommandContainer
    {
        public ScrollPanel()
            : base()
        {
            Init();
        }
        public ScrollPanel(int x, int y, int width, int height)
            : base()
        {
            Init();
            Bounds = new Rectangle(x, y, width, height);
        }

        public override void Dispose()
        {
            transparentBrush.Dispose();
            if (BackGroundImage != null)
            {
                BackGroundImage.Dispose();
            }
            base.Dispose();
        }

        private void Init()
        {

            BeginInit();
            this.EnableDoubleBuffer = true;
            this.BackColor = Color.White;
            Controls.ControlAdded += new EventHandler<ControlEventArgs>(Controls_ControlAdded);
            DirectUITextBox.InputPanel.EnabledChanged += new EventHandler(InputPanel_EnabledChanged);

            EndInit();
        }




        void Controls_ControlAdded(object sender, ControlEventArgs e)
        {
            // CalOffset();
            displayHeight = GetVirtualHeight();
            e.Control.SizeChanged += new EventHandler<ChangedEventArgs<Size>>(Control_SizeChanged);
        }
        public void ResetDisplayHeight()
        {
            displayHeight = GetVirtualHeight();
        }
        void Control_SizeChanged(object sender, ChangedEventArgs<Size> e)
        {
            displayHeight = GetVirtualHeight();
        }


        /// <summary>
        /// dictionary of all cached bitmaps for each control.
        /// </summary>
        private HybridDictionary imageBuffer = new HybridDictionary();

        public override void OnKeyPress(KeyPressEventArgs e)
        {
            if (e.KeyChar == '\t')
            {
                e.Handled = true;
                SelectNextControl();
            }
        }






        /// <summary>
        /// Gets the collection of all TouchControls inside this panel.
        /// </summary>
        /// <value></value>
        public DirectUIControlCollection Controls { get { return controls; } }

        public override void Scale(SizeF scaleFactor)
        {
            base.Scale(scaleFactor);
            displayHeight = GetVirtualHeight();
        }
        private int displayHeight;
        public override int DisplayHeight
        {
            get
            {
                //if (DirectUITextBox.InputPanel.Enabled)
                //{
                //    return displayHeight + DirectUITextBox.InputPanel.Bounds.Height;
                //}
                //else
                //{
                    return displayHeight;
                //}
            }
        }
        public override bool Active { get { return true; } }
        private int GetVirtualHeight()
        {
            int height = this.Height;
            foreach (DirectUIControl c in controls)
            {
                height = Math.Max(height, c.Bounds.Bottom);
            }
            return height;
        }


        //     int[] _itemOffset = null;
        private Dictionary<string, Rectangle> _itemOffset = new Dictionary<string, Rectangle>();
        private void CalOffset()
        {

            for (int i = 0; i < this.Controls.Count; i++)
            {

                if (string.IsNullOrEmpty(this.Controls[i].Name))
                {
                    this.Controls[i].Name = (Guid.NewGuid()).ToString();
                }
                if (!_itemOffset.ContainsKey(this.Controls[i].Name))
                {
                    _itemOffset.Add(this.Controls[i].Name, this.Controls[i].Bounds);
                }
            }

        }
   
    
        /// <summary>
        /// Paints this control double buffered.
        /// </summary>
        /// <param name="pe">The  paint event args.</param>
        protected override void PaintContent(DirectUIPaintEventArgs pe)
        {
      
           base.PaintContent(pe);
           
            PaintControls(pe);
        }
        private Region invalidRegion;
        private Bitmap dbuffer;

        private void EnsureDBuffer(Rectangle rec)
        {
            if (dbuffer == null || dbuffer.Width != rec.Width || dbuffer.Height != rec.Height)
            {
                if (dbuffer != null) dbuffer.Dispose();
                int w = Math.Max(1, rec.Width);
                int h = Math.Max(1, rec.Height);
                dbuffer = new Bitmap(w, h);
                EnsureRegion();
                invalidRegion.MakeInfinite();
            }
        }

        private void EnsureRegion()
        {
            if (invalidRegion == null)
            {
                invalidRegion = new Region();
                invalidRegion.MakeInfinite();
            }
        }
        private DirectUIPaintEventArgs paintEvents;
        private void EnsurePaintEvents()
        {
            if (paintEvents == null) paintEvents = new DirectUIPaintEventArgs();
        }
        /// <summary>
        /// Paints all  controls.
        /// </summary>
        /// <param name="pe">The PaintEventArgs.</param>
        //private void PaintControls(DirectUIPaintEventArgs pe)
        //{
        //    Rectangle controlBounds = pe.ControlBounds;
        //    Graphics g = pe.Graphics;
        //    Region clip = pe.Region;
        //    foreach (DirectUIControl c in controls)
        //    {
        //        if (!c.Visible) continue;
        //        Rectangle bounds = c.Bounds;
        //        //if (!_itemOffset.ContainsKey(c.Name))
        //        //{
        //        //    CalOffset();
        //        //}
        //    //    bounds = new Rectangle(bounds.X, bounds.Y - PaintTop, bounds.Width, bounds.Height);
        //        if (clip.IsVisible(bounds))
        //        {
        //            //if (this.EnableDoubleBuffer)
        //            //{
        //            //    PaintControlDoubleBuffered(pe, c, bounds);
        //            //}
        //            //else
        //            //{
        //            PaintControlUnbuffered(pe, c, bounds);
        //            //     }
        //        }
        //    }

        //}

        ///// <summary>
        ///// Paints all  controls.
        ///// </summary>
        ///// <param name="pe">The PaintEventArgs.</param>
        //private void PaintControls(DirectUIPaintEventArgs pe)
        //{
        //    Rectangle bounds = pe.ControlBounds;
        //    for(int i=0;i<this.Controls.Count;i++)
        //    {
        //        DirectUIControl c = this.Controls[i];
        //        if (!c.Visible) continue;
        //   //     if (invalidRegion.IsVisible(c.Bounds))
        //      //  {
        //        if (!_itemOffset.ContainsKey(c.Name))
        //        {
        //            CalOffset();
        //        }
        //            c.Top = _itemOffset[c.Name] - PaintTop;
        //            pe.ControlBounds = c.Bounds;
        //            c.OnPaint(paintEvents);
        //    //    }

        //    }

        //}

        private DirectUIPaintEventArgs paintEventArgs2 = new DirectUIPaintEventArgs();

      protected  void   PaintControlUnbuffered(DirectUIPaintEventArgs pe, DirectUIControl control, Rectangle bounds)
        {
            
            //bounds.Offset(Left, Top);
            //Region clp = pe.IntersectClip(bounds);
            DirectUIPaintEventArgs e = paintEventArgs2;
            e.Graphics = pe.Graphics;
            e.ControlBounds = bounds;
            //  e.ControlBounds.Offset(0, PaintTop);
            e.Region = pe.Region;
            e.ScaleFactor = pe.ScaleFactor;
            control.OnPaint(e);
            //pe.ResetClip(clp);
        }

        private Color transparentColor = Color.Fuchsia;

        /// <summary>
        /// Gets or sets the color that is used as transparent color when EnableDoubleBuffer is set to true.
        /// see also <seealso cref="EnabledDoubleBuffer"/>.
        /// </summary>
        public Color TransparentColor
        {
            get { return transparentColor; }
            set { transparentColor = value; }
        }

        private DirectUIPaintEventArgs paintEventArgs = new DirectUIPaintEventArgs();
        private SolidBrush transparentBrush = new SolidBrush(Color.Transparent);

        private void PaintControlDoubleBuffered(DirectUIPaintEventArgs pe, DirectUIControl control, Rectangle bounds)
        {
            Bitmap buffer;
            if (imageBuffer.Contains(control))
            {
                buffer = imageBuffer[control] as Bitmap;
            }
            else
            {
                buffer = new Bitmap(bounds.Width, bounds.Height);
                imageBuffer.Add(control, buffer);
                using (Graphics bg = Graphics.FromImage(buffer))
                {
                    this.transparentBrush.Color = transparentColor;
                    bg.FillRectangle(transparentBrush, 0, 0, buffer.Width, buffer.Height);
                    Rectangle paintRect = control.ClientRectangle;
                    //bg.Clear(transparentColor);

                    DirectUIPaintEventArgs e = paintEventArgs;
                    e.Graphics = bg;
                    e.ControlBounds = paintRect;
                    e.Region = bg.Clip;
                    e.ScaleFactor = pe.ScaleFactor;
                    control.OnPaint(e);
                }

            }
            ia.SetColorKey(transparentColor, transparentColor);
            pe.Graphics.DrawImage(buffer, bounds, 0, 0, bounds.Width, bounds.Height, GraphicsUnit.Pixel, ia);
        }

        ImageAttributes ia = new ImageAttributes();

        Rectangle IContainer.GetScreenBounds(Rectangle bounds)
        {
            bounds.Offset(Left, Top - ScaledTopOffset);
            if (Container != null)
            {
                return Container.GetScreenBounds(bounds);
            }
            return bounds;
        }

        //public override void Invalidate(Rectangle bounds)
        //{
        //    //if (Initializing) return;
        //    //if (Container == null) return;
        //    //if (!bounds.IsEmpty)
        //    //{
        //    //    bounds.Offset(Left, Top - ScaledTopOffset);
        //    //    //// don't let the child control invalidate anything outside the own bounds:
        //    //    ClipRectangle(ref bounds);
        //    //   if (!bounds.Size.IsEmpty) Container.Invalidate(bounds);
        //    //}

        // // //  EnsureDBuffer(this.Bounds);
        // //   if (invalidRegion != null)
        // //   {
        // //       invalidRegion.Union(bounds);
        // //   }
        // ////   base.Invalidate(bounds);

        //}

        //public override void Invalidate()
        //{
        //    if (Initializing) return;
        //    base.Invalidate();
        //    if (invalidRegion != null)
        //    {
        //        invalidRegion.MakeInfinite();
        //    }
        //   // InvalidateChildren();
        //}



        //private void InvalidateChildren()
        //{
        //    return; // debug==
        //    //foreach (DirectUIControl c in controls)
        //    //{
        //    //    if (c.IsTransparent) c.Invalidate();
        //    //}
        //}

        //  private DirectUIControl downControl = null;


        //private PointEventArgs TranslatePoint(DirectUIControl c, PointEventArgs p)
        //{
        //    p.X -= c.Bounds.X;
        //    p.Y -= c.Bounds.Y;
        //    //PointEventArgs e = new PointEventArgs(p.Gesture, p.X - c.Bounds.X, p.Y - c.Bounds.Y);
        //    return p;
        //}

        //public override void OnGesture(GestureEventArgs e)
        //{
        //    base.OnGesture(e);
        //    if (downControl != null) downControl.OnGesture(e);
        //}

        //public override void OnMove(PointEventArgs p)
        //{
        //    base.OnMove(p);
        //    if (downControl != null) downControl.OnMove(this.TranslatePoint(downControl, p));
        //}

        //public override void OnRelease(PointEventArgs p)
        //{
        //    base.OnRelease(p);
        //    if (downControl != null) downControl.OnRelease(this.TranslatePoint(downControl, p));
        //}

        // private DirectUIControl selectedControl;

        //public override void OnDown(PointEventArgs p)
        //{
        //    base.OnDown(p);
        //    DirectUIControl control = ControlFromPoint(p.X, p.Y);
        //    downControl = control;
        //    if (control != null)
        //    {
        //        PointEventArgs p2 = TranslatePoint(control, p);
        //        control.OnDown(p2);
        //    }
        //    if (control != null && control.Selectable)
        //    {
        //        selectedControl = control;
        //    }
        //    else if (control == null)
        //    {
        //        selectedControl = null;
        //    }
        //}

        //public override void OnUp(PointEventArgs p)
        //{
        //    base.OnUp(p);
        //    if (downControl != null) downControl.OnUp(TranslatePoint(downControl, p));

        //}

        //public override bool OnClick(PointEventArgs p)
        //{
        //    base.OnClick(p);
        //    if (downControl != null) downControl.OnClick(TranslatePoint(downControl, p));
        //    return true;
        //}

        

        /// <summary>
        /// Gets the first control that is under the specified point.
        /// </summary>
        /// <param name="x">The x value of the point.</param>
        /// <param name="y">The y value of the point.</param>
        /// <returns>An ITouchControl, otherwise null.</returns>
        /// <remarks>
        /// The enumeration starts from the last to the first control, because the controls appear in this
        /// order in case they are overlapping.
        /// </remarks>
        // public DirectUIControl ControlFromPoint(int x, int y)
        // {
        //     Point p = checkPoint; 
        //     p.X = x;
        ////     p.Y = y + TopOffset;
        //     p.Y = y;
        //     for (int i = controls.Count - 1; i >= 0; i--)
        //     {
        //         DirectUIControl c = controls[i];
        //         if (!c.Visible) continue;
        //         Rectangle r = c.Bounds;
        //         if (r.Contains(p)) return c;
        //     }
        //     return null;
        // }

        //protected override void BeginMoving()
        //{
        //    base.BeginMoving();
        //    selectedControl = null;
        //}

        //public override void OnKeyDown(KeyEventArgs e)
        //{          
        //    StopAutoScroll();
        //    base.OnKeyDown(e);
        //}

        void ControlKeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == '\t')
            {
                e.Handled = true;
                SelectNextControl();
            }
        }

        void ControlKeyDown(object sender, KeyEventArgs e)
        {
            //switch (e.KeyCode)
            //{
            //    case Keys.Escape:
            //        e.Handled = true;
            //        SelectedPage = null;
            //        break;

            //    case Keys.Down:
            //    case Keys.Tab:
            //        e.Handled = true;
            //        SelectNextControl();
            //        break;

            //    case Keys.Up:
            //        e.Handled = true;
            //        SelectPreviousControl();
            //        break;
            //}
        }

        public virtual void SelectNextControl()
        {
            throw new ArgumentException("Not implemententad");
            //int index = SelectedPage != null ? controls.IndexOf(SelectedPage) : -1;
            //int n = controls.Count;
            //for (int i = 1; i <= n; i++)
            //{
            //    int idx = i + index;
            //    if (idx >= n) idx -= n;
            //    DirectUIControl c = controls[idx];
            //    if (c.Selectable)
            //    {
            //        SelectedPage = c;
            //        return;
            //    }
            //}
        }

        public virtual void SelectPreviousControl()
        {
            throw new ArgumentException("Not implemententad");
            //int index = SelectedPage != null ? controls.IndexOf(SelectedPage) : controls.Count;
            //int n = controls.Count;
            //index = n - index;
            //for (int i = n - 1; i >= 0; i--)
            //{
            //    int idx = i - index;
            //    if (idx < 0) idx += n;
            //    DirectUIControl c = controls[idx];
            //    if (c.Selectable)
            //    {
            //        SelectedPage = c;
            //        return;
            //    }
            //}
        }


        /// <summary>
        /// Ensure that the specified control is visible, and make it become visible if not.
        /// </summary>
        /// <param name="c">The control that needs to be visible.</param>
        /// <returns>True, if the control was already visible, otherwise false.</returns>
        public bool EnsureVisible(DirectUIControl c)
        {
            bool result = true;
            Rectangle bounds = c.Bounds;
            bounds.Y -= TopOffset;
            Rectangle clientBounds = Bounds;
            int maxHeight = GetMaxHeight();
            if (maxHeight < clientBounds.Height)
            {
                clientBounds.Height = maxHeight;
            }
            if (!clientBounds.Contains(bounds))
            {
                EnsureVisible(bounds);
            }
            return result;
        }

    

        public Point PointToHost(int x, int y)
        {
            return Container.PointToHost(x + Left, y + Top);
        }

        #region IControlContainer Members


        #endregion


        protected override void OnSizeChanged(Size oldSize, Size newSize)
        {
            imageBuffer.Clear();
            displayHeight = this.Height;
            base.OnSizeChanged(oldSize, newSize);
            // Layout(oldSize, newSize);
        }

        protected override void OnTopOffsetChange(int actualValue, int newValue)
        {
            LeaveDescendant();
            base.OnTopOffsetChange(actualValue, newValue);

        }
        /// <summary>
        /// Removes the focus of the selected control, if this control is a parent of the selected control.
        /// </summary>
        private void LeaveDescendant()
        {
            if (Container == null)
            {
                return;
            }
            DirectUIControl selected = Container.Host.FocusedControl;
            if (selected != null)
            {
                if (selected.IsDescendantOf(this))
                {
                    Container.Host.FocusedControl = this;
                }
            }
        }


        #region ICommandContainer Members

        public virtual void RaiseCommand(CommandEventArgs e)
        {
            if (Command != null)
            {
                Command(this, e);
            }
            if (!e.Handled)
            {
                ICommandContainer container = this.Container as ICommandContainer;
                if (container != null)
                {
                    container.RaiseCommand(e);
                }
            }
        }

        public new event EventHandler<CommandEventArgs> Command;
        private DirectUIControl _inputControl;
        /// <summary>
        /// when the InputPanel appears, make sure that the selected item is visible by changing
        /// the MaxValue for the display height:
        /// </summary>
        void InputPanel_EnabledChanged(object sender, EventArgs e)
        {
            if (Host == null) return;
            if (!Host.Visible) return;
            InputPanel inputPanel = DirectUITextBox.InputPanel;
            bool enabled = inputPanel.Enabled;

            Rectangle bounds = inputPanel.Bounds;
            Rectangle hostBounds = this.ScreenBounds;
            int height = hostBounds.Height;

            if (enabled)
            {
                if (hostBounds.Bottom > bounds.Top)
                {
                    height = bounds.Top - hostBounds.Top;
                }
             //   this.displayHeight += inputPanel.Bounds.Height;
            }
            else
            {
             //   this.displayHeight -= inputPanel.Bounds.Height;

            }
            maxHeight = Math.Max(0, height);
            if (enabled)
            {
                if (downControl != null)
                {
                    _inputControl = downControl;
                    EnsureVisible(downControl);
                    _inputControl.Focus();
                }
                //else if (_inputControl != null&&downControl==null)
                //{
                //    downControl = _inputControl;
                //    EnsureVisible(downControl);
                //}
            }
            else EnsureValidPosition();
        }
        int maxHeight = int.MaxValue;

        protected override int GetMaxHeight()
        {
            int max = base.GetMaxHeight();
            return Math.Min(maxHeight, max);
        }
        #endregion
    }
}
